﻿/*
*	Copyright(c) 2020 lutianming email：641471957@qq.com
*
*	Sheeps may be copied only under the terms of the GNU Affero General Public License v3.0
*/

#include "framework.h"
#include "SheepsFactory.h"
#include "AgentManager.h"
#include "SheepsMain.h"
#include "AgentProtocol.h"
#include "ServerHook.h"
#include <thread>

#ifdef __WINDOWS__
#include "shellapi.h"

#define AtomicAdd(a, b) InterlockedExchangeAdd(&a, b)
#define AtomicSub(a, b) InterlockedExchangeAdd(&a, -b)
#define AtomicChg(a, b) InterlockedExchange(&a, b)
#else
#define AtomicAdd(a, b) __sync_fetch_and_add(&a, b)
#define AtomicSub(a, b) __sync_fetch_and_sub(&a, b)
#define AtomicChg(a, b) __sync_lock_test_and_set(&a, b)
#endif

int			projectid = 0;

bool TaskManagerRuning = false;
int	 TaskAgentState = STATE_READY_NONE;
char TaskAgentStatMsg[256] = { 0x0 };
char TaskAgentWelcome[256] = { 0x0 };
char TaskAgentInfoString[1024] = { 0x0 };

bool log_stdout = false;

static const char* EMPTY_STRING = "";

std::map<int, ClientTaskConfig*>* taskAll = new(std::nothrow) std::map<int, ClientTaskConfig*>;
std::map<int, ClientTaskConfig*>* taskClean = new(std::nothrow) std::map<int, ClientTaskConfig*>;

ReplayProtocol* userFree = new HeadProtocol();
t_replay_callback default_api = { 0x0 };

void __STDCALL task_agent_stat_msg_set(int state, const char* msg){
	TaskAgentState = state;
	snprintf(TaskAgentStatMsg, sizeof(TaskAgentStatMsg), "%s", msg);
}

void __STDCALL task_agent_welcome_set(const char* msg) {
	snprintf(TaskAgentWelcome, sizeof(TaskAgentWelcome), "%s", msg);
}

static inline void user_report_stop(ClientTaskConfig* task, ReplayProtocol* user) {
	char buf[256] = { 0x0 };
	snprintf(buf, sizeof(buf), "%d|%d|%d|%s|%s", task->machineID, user->UserNumber, user->_fram_data.RunTime, user->stop_reason, user->stop_reason + UserErrorSize);
	task->reportData.error_lock->lock();
	task->reportData.error1->push_back(buf);
	task->reportData.error_lock->unlock();
}

static inline void update_user_time_clock(ReplayProtocol* proto){
	HMSGPOINTER pointer = &proto->_fram_data.MsgPointer;
	if (pointer->last > 0){
		uint32_t nowtime = uint32_t(GetSysTimeMicros() / 1000);   //毫秒
		pointer->start_real += nowtime - pointer->last;
		pointer->last = nowtime;
	}
}

static inline ReplayProtocol* get_user_from_free(ClientTaskConfig* task){
	ReplayProtocol* user, *next;
	user = userFree->next;
	if (user != userFree) {
		next = user->next;
		next->prev = userFree;
		userFree->next = next;
	}
	else {
		user = default_api.create();
		user->auto_release(false);
	}
	return user;
}

static void push_user_to_free(BaseWorker* worker, void* user_data) {
	/*delete from task user list*/
	ReplayProtocol* user = (ReplayProtocol*)user_data;
	ReplayProtocol* prev = user->prev;
	ReplayProtocol* next = user->next;
	prev->next = next;
	next->prev = prev;

	/*add to userFree tail*/
	prev = userFree->prev;
	prev->next = user;
	user->next = userFree;
	userFree->prev = user;
	user->prev = prev;
}

static inline void push_userDes_back(ClientTaskConfig* task, ReplayProtocol* user){
	PostEvent(AgentProto, user, push_user_to_free);
}

static inline void call_user_init(ClientTaskConfig* task, ReplayProtocol* user) {
	user->user_status.Destroyed = false;
	user->_fram_data.RunTime = (int)NOWTIME;
	//user->user_status.AutoStop = task->autoStop;
	user->lastWatchDog = NOWTIME;
	user->EventStart();
}

static void call_user_stop(hClientTaskConfig task, ReplayProtocol* user, bool loop) {
	user->EventStop();
	ReportOffline(user);
	user->_UserTimeOut();
	if (!loop) {
		user->thread_unset();
		user->_fram_data.RunTime = (int)NOWTIME - user->_fram_data.RunTime;
		user_report_stop(task, user);
	}
	user->ConnectionCloseAll();
	user->_fram_data = { 0x0 };
	user->user_status.PlayPause = false;
#ifdef USER_PAUSE_COUNT
	user->user_pause_count = 0;
#endif
	user->user_status.PlayStop = false;
	user->user_status.NotAutoStop = false;
	user->user_status.Destroyed = true;
	*(user->stop_reason) = 0x0;
}

static inline void call_user_timeout(ReplayProtocol* user) {
	user->_UserTimeOut();
	user->EventTimeOut();
}

static HMESSAGE task_get_next_message(ReplayProtocol* proto, bool normal){
	HMSGPOINTER pointer = &(proto->_fram_data.MsgPointer);
	hClientTaskConfig task = proto->Task;
	if (pointer->index < task->messageList->size()){
		t_cache_message* msg = (*(task->messageList))[pointer->index];
		uint32_t nowtime = uint32_t(GetSysTimeMicros()/1000);  //获取当前时间，毫秒
		if (pointer->index == 0){  //获取第一条用例时，记录开始时间
			pointer->start_real = nowtime;
		}
		if (normal) {   //正常播放状态，判断时间是否足够
			if (nowtime - pointer->start_real < msg->recordtime){
				//printf("%s:%d %d %u %u\n", __func__, __LINE__, msg->type, nowtime - pointer->start_real, msg->recordtime);
				return NULL;
			}
			//printf("%s:%d %d %u %u\n", __func__, __LINE__, msg->type, nowtime - pointer->start_real, msg->recordtime);
		}
		else{  //快进状态下，重置开始时间，从当前时间往前数当前用例时间长度
			pointer->start_real = nowtime - msg->recordtime;
		}
		pointer->last = nowtime;
		pointer->index++;
		return msg;
	}
	else {
		if (task->stopMessageCache) proto->user_status.PlayStop = true;    //proto->user_status.NotAutoStop 设置为true时需要此代码
	}
	return NULL;
}

static void ReInit(hClientTaskConfig task, ReplayProtocol* proto, bool loop) {
	if (proto->user_status.NotAutoStop) {
		proto->user_status.PlayPause = true;
#ifdef USER_PAUSE_COUNT
		proto->user_pause_count++;
#endif
	}
	else if (loop) {
		call_user_stop(task, proto, loop);
		call_user_init(task, proto);
	}
	else {
		proto->user_status.PlayStop = true;
	}
}

static void Loop(hClientTaskConfig task, ReplayProtocol* proto){
	call_user_timeout(proto);

	if (proto->user_status.PlayPause) {
		update_user_time_clock(proto);
		return;
	}

	HMESSAGE message = task_get_next_message(proto, !proto->user_status.PlayFast);
	if (!message) return;
	switch (message->event){
	case TYPE_CONNECT: /*连接事件*/
		proto->ConnectionOpen(message->ip, message->port, message->protocol);
		break;
	case TYPE_CLOSE:	/*关闭连接事件*/
		proto->ConnectionClose(message->ip, message->port, message->protocol);
		break;
	case TYPE_SEND:	/*向连接发送消息事件*/
		proto->ConnectionSend(message->ip, message->port, message->content, (int)message->contentlen, message->protocol);
		break;
	case TYPE_REINIT:	/*用户重置事件，关闭所有连接，初始化用户资源*/
		ReInit(task, proto, message->isloop);
		break;
	default:
		break;
	}
	return;
}


void  userWorkFunc(HTIMER hsock, BaseWorker* user, void* user_data){
	ReplayProtocol* proto = (ReplayProtocol*)user;
	ClientTaskConfig* task = proto->Task;

	if (!proto->user_status.PlayStop){
		Loop(task, proto);
	}
	else{
		if (task->ignoreErr){
			ReInit(task, proto, true);
			//*(proto->stop_reason) = 0x0;
		}
		else{
			call_user_stop(task, proto, false);
			TimerDelete(hsock);
			proto->_timer = NULL;
			push_userDes_back(task, proto);
		}
	}
}

static void signal_call_user_stop(BaseWorker* user, long long signal) {
	ReplayProtocol* proto = (ReplayProtocol*)user;
	if (proto->user_status.Destroyed)
		return;

	hClientTaskConfig task = proto->Task;
	if (!proto->user_status.PlayStop) {
		snprintf(proto->stop_reason, UserErrorSize, "强制结束");
	}
	call_user_stop(task, proto, false);
	TimerDelete(proto->_timer);
	proto->_timer = NULL;
	push_userDes_back(task, proto);
}

static void destroy_task(hClientTaskConfig task){
	LOG(clogId, LOG_DEBUG, "%s:%d Start Clean Task !\r\n", __func__, __LINE__);
	//ReplayProtocol*head = task->user_head, *next = NULL;
	//next = head->next;
	//LOG(clogId, LOG_DEBUG, "%s:%d Start Stop Task User!\r\n", __func__, __LINE__);
	//while (next != head){
	//	LOG(clogId, LOG_DEBUG, "%s:%d Start Clean Task User[%d]!\r\n", __func__, __LINE__, next->UserNumber);
	//	next->EventStopSignal();  //提前发送一个信号，让用户在代码中间退出，主要用于处理死循环
	//	if (next->thread_id > -1) PostSignal(next, 0, signal_call_user_stop);
	//	next = next->next;
	//	LOG(clogId, LOG_DEBUG, "%s:%d Clean Task User[%d] EventDestroy Over!\r\n", __func__, __LINE__, next->UserNumber);
	//	TimeSleep(1);
	//}
	//LOG(clogId, LOG_DEBUG, "%s:%d Start Stop Task User Over!\r\n", __func__, __LINE__);

	//while (head != head->next) {
	//	TimeSleep(1000);
	//}
	//delete task->user_head;
	//LOG(clogId, LOG_DEBUG, "%s:%d Clean User All Over!\r\n", __func__, __LINE__);

	if (default_api.taskstop){
		default_api.taskstop(task);
	}

	std::vector<t_cache_message*>::iterator it;
	t_cache_message* data;
	for (it = task->messageList->begin(); it != task->messageList->end(); ++it){
		data = *it;
		if (data->content && data->content != EMPTY_STRING) free(data->content);
		if (data->note && data->note != EMPTY_STRING) free(data->note);
		free(data);
		*it = NULL;
		TimeSleep(1);
	}
	task->messageList->clear();
	delete task->messageList;
	LOG(clogId, LOG_DEBUG, "%s:%d Clean Task Message Over!\r\n", __func__, __LINE__);
	CloseLog(task->logfd);
	task->status = TASK_CLEANED;
	LOG(clogId, LOG_DEBUG, "%s:%d Clean Task Running Data Over!\r\n", __func__, __LINE__);
}

static void destroy_task_stop_user(HTIMER timer, BaseWorker* work, void* data) {
	hClientTaskConfig task = (hClientTaskConfig)data;
	ReplayProtocol* head = task->user_head;
	ReplayProtocol* next = head->next;
	if (next != head) {
		if (next != task->user_stop) {
			LOG(clogId, LOG_DEBUG, "%s:%d Start Clean Task User[%d]!\r\n", __func__, __LINE__, next->UserNumber);
			next->EventStopSignal();  //提前发送一个信号，让用户在代码中间退出，主要用于处理死循环
			if (next->thread_id > -1) PostSignal(next, 0, signal_call_user_stop);
			LOG(clogId, LOG_DEBUG, "%s:%d Clean Task User[%d] EventDestroy Over!\r\n", __func__, __LINE__, next->UserNumber);
			task->user_stop = next;
		}
	}
	else {
		LOG(clogId, LOG_DEBUG, "%s:%d Start Stop Task User Over!\r\n", __func__, __LINE__);
		delete task->user_head;
		LOG(clogId, LOG_DEBUG, "%s:%d Clean User All Over!\r\n", __func__, __LINE__);
		std::thread th(destroy_task, task);
		th.detach();
		TimerDelete(timer);
	}
}

//static bool run_task_stop_thread(hClientTaskConfig task){
//	std::thread th(destroy_task, task);
//	th.detach();
//	return true;
//}

void task_free_data() {
	ClientTaskConfig* task = NULL;
	std::map<int, ClientTaskConfig*>::iterator iter;
	for (iter = taskClean->begin(); iter != taskClean->end(); ) {
		task = iter->second;
		if (task->status == TASK_REPORTED) {
			std::map<std::string, AgentReportInfoConnect*>::iterator iter_connect;
			for (iter_connect = task->reportData.connect->begin(); iter_connect != task->reportData.connect->end();) {
				free(iter_connect->second);
				task->reportData.connect->erase(iter_connect++);
			}
			delete task->reportData.connect;
			delete task->reportData.connect_lock;
			std::map<std::string, AgentReportInfoCounter*>::iterator iter_custom;
			for (iter_custom = task->reportData.counter->begin(); iter_custom != task->reportData.counter->end();) {
				free(iter_custom->second);
				task->reportData.counter->erase(iter_custom++);
			}
			delete task->reportData.counter;
			delete task->reportData.counter_lock;
			std::map<std::string, AgentReportInfoApi*>::iterator iter_api;
			for (iter_api = task->reportData.api->begin(); iter_api != task->reportData.api->end();) {
				AgentReportInfoApi* info = iter_api->second;
				info->data1->clear();
				info->data2->clear();
				delete info->data1;
				delete info->data2;
				delete info->data_lock;
				free(info);
				task->reportData.api->erase(iter_api++);
			}
			delete task->reportData.api;
			delete task->reportData.api_lock;

			task->reportData.error1->clear();
			task->reportData.error2->clear();
			delete task->reportData.error1;
			delete task->reportData.error2;
			delete task->reportData.error_lock;
			LOG(clogId, LOG_DEBUG, "%s:%d Free Task Report Over!\r\n", __func__, __LINE__);
			if (task->report_log) {
				AgentProto->TaskTeportLogInsert(task->taskID, task->projectID, task->machineID);
			}
			free(task);
			LOG(clogId, LOG_DEBUG, "%s:%d Free Task Over!\r\n", __func__, __LINE__);
			taskClean->erase(iter++);
		}
		else {
			iter++;
		}
	}
}

static ClientTaskConfig* task_new_data(int task_id) {
	hClientTaskConfig task = (hClientTaskConfig)malloc(sizeof(ClientTaskConfig));
	if (task == NULL){
		return NULL;
	}
	memset(task, 0x0, sizeof(ClientTaskConfig));
	
	ReplayProtocol* user = new HeadProtocol();
	task->user_head = user;

	task->messageList = new(std::nothrow) std::vector<t_cache_message*>;
	task->reportData.connect = new(std::nothrow) std::map<std::string, AgentReportInfoConnect*>;
	task->reportData.connect_lock = new(std::nothrow) std::mutex;
	task->reportData.counter = new(std::nothrow) std::map<std::string, AgentReportInfoCounter*>;
	task->reportData.counter_lock = new(std::nothrow) std::mutex;
	task->reportData.api = new(std::nothrow) std::map<std::string, AgentReportInfoApi*>;
	task->reportData.api_lock = new(std::nothrow) std::mutex;
	task->reportData.error1 = new(std::nothrow) std::vector<std::string>;
	task->reportData.error2 = new(std::nothrow) std::vector<std::string>;
	task->reportData.error_lock = new(std::nothrow) std::mutex;


	if (!task->messageList ||
		!task->reportData.connect || !task->reportData.counter || !task->reportData.api ||
		!task->reportData.connect_lock || !task->reportData.counter_lock || !task->reportData.api_lock ||
		!task->reportData.error1 || !task->reportData.error2 || !task->reportData.error_lock){
		LOG(clogId, LOG_ERROR, "%s:%d malloc error\r\n", __func__, __LINE__);
		if (task->messageList) delete task->messageList;
		if (task->reportData.connect) delete task->reportData.connect;
		if (task->reportData.connect_lock) delete task->reportData.connect_lock;
		if (task->reportData.counter) delete task->reportData.counter;
		if (task->reportData.counter_lock) delete task->reportData.counter_lock;
		if (task->reportData.api) delete task->reportData.api;
		if (task->reportData.api_lock) delete task->reportData.api_lock;
		if (task->reportData.error1) delete task->reportData.error1;
		if (task->reportData.error2) delete task->reportData.error2;
		if (task->reportData.error_lock) delete task->reportData.error_lock;
		free(task);
		return NULL;
	}
	taskAll->insert(std::pair<int, hClientTaskConfig>(task_id, task));
	return task;
}

static bool task_push_report_data_detail(cJSON* array, ClientTaskConfig* task) {
	if (task->status == TASK_CLEANED) task->status = TASK_REPORTED;

	cJSON* task_root = cJSON_CreateObject();
	bool task_flag = false;

	long online = AtomicChg(task->reportData.user_online, 0);
	if (online) {
		cJSON_AddNumberToObject(task_root, "online", online);
		task_flag = true;
	} 

	if (!task->reportData.connect->empty()) {
		cJSON* connect = cJSON_CreateArray();
		bool flag = false;
		std::map<std::string, AgentReportInfoConnect*>::iterator iter_connect;
		for (iter_connect = task->reportData.connect->begin(); iter_connect != task->reportData.connect->end(); ++iter_connect) {
			AgentReportInfoConnect* info = iter_connect->second;
			long success = AtomicChg(info->success, 0);
			long faile = AtomicChg(info->faile, 0);
			long app_flow_up = AtomicChg(info->app_flow_up, 0);
			long app_flow_down = AtomicChg(info->app_flow_down, 0);
			long net_flow_up = AtomicChg(info->net_flow_up, 0);
			long net_flow_down = AtomicChg(info->net_flow_down, 0);
			if (!success && !faile && !app_flow_up && !app_flow_down && !net_flow_up && !net_flow_down) continue;
			cJSON* item = cJSON_CreateObject();
			cJSON_AddStringToObject(item, "addr", iter_connect->first.c_str());
			if (success) cJSON_AddNumberToObject(item, "success", success);
			if (faile) cJSON_AddNumberToObject(item, "faile", faile);
			if (app_flow_up) cJSON_AddNumberToObject(item, "flow_up", app_flow_up);
			if (app_flow_down) cJSON_AddNumberToObject(item, "flow_down", app_flow_down);
			if (net_flow_up) cJSON_AddNumberToObject(item, "net_flow_up", net_flow_up);
			if (net_flow_down) cJSON_AddNumberToObject(item, "net_flow_down", net_flow_down);
			cJSON_AddItemToArray(connect, item);
			flag = true;
		}
		if (flag) {
			cJSON_AddItemToObject(task_root, "connect", connect);
			task_flag = true;
		}
		else cJSON_Delete(connect);
	}
	if (!task->reportData.counter->empty()) {
		cJSON* counter = cJSON_CreateArray();
		bool flag = false;
		std::map<std::string, AgentReportInfoCounter*>::iterator iter_counter;
		for (iter_counter = task->reportData.counter->begin(); iter_counter != task->reportData.counter->end(); ++iter_counter) {
			AgentReportInfoCounter* info = iter_counter->second;
			long  value = AtomicChg(info->value, 0);
			if (value) {
				cJSON* item = cJSON_CreateObject();
				cJSON_AddStringToObject(item, "name", iter_counter->first.c_str());
				cJSON_AddNumberToObject(item, "stype", info->stype);
				cJSON_AddNumberToObject(item, "value", value);
				cJSON_AddNumberToObject(item, "space_time", info->space_time);
				cJSON_AddItemToArray(counter, item);
				flag = true;
			}
		}
		if (flag) {
			cJSON_AddItemToObject(task_root, "counter", counter);
			task_flag = true;
		}
		else cJSON_Delete(counter);
	}
	
	if (!task->reportData.api->empty()) {
		//cJSON* api = cJSON_AddArrayToObject(task_root, "api");
		cJSON* api = cJSON_CreateArray();
		bool flag = false;
		cJSON* item = NULL;
		AgentReportInfoApi* info;
		std::map<std::string, AgentReportInfoApi*>::iterator iter_api;
		for (iter_api = task->reportData.api->begin(); iter_api != task->reportData.api->end(); ++iter_api) {
			info = iter_api->second;
			item = NULL;

			info->data_lock->lock();
			std::swap(info->data1, info->data2);
			info->data_lock->unlock();
			std::vector<unsigned short>* data = info->data2;
			
			long send_flow = AtomicChg(info->send_flow, 0);
			long send_count = AtomicChg(info->send_count, 0);
			if (send_flow) {
				if (!item) item = cJSON_CreateObject();
				cJSON_AddNumberToObject(item, "send_flow", send_flow);
				cJSON_AddNumberToObject(item, "send_count", send_count);
				flag = true;
			}
			long recv_flow = AtomicChg(info->recv_flow, 0);
			long recv_count = AtomicChg(info->recv_count, 0);
			if (recv_flow) {
				if (!item) item = cJSON_CreateObject();
				cJSON_AddNumberToObject(item, "recv_flow", recv_flow);
				cJSON_AddNumberToObject(item, "recv_count", recv_count);
				flag = true;
			}
			long error_count = AtomicChg(info->error_count, 0);
			if (error_count) {
				if (!item) item = cJSON_CreateObject();
				cJSON_AddNumberToObject(item, "error", error_count);
				flag = true;
			}
			if (!data->empty()) {
				if (!item) item = cJSON_CreateObject();
				cJSON* array_res = cJSON_AddArrayToObject(item, "response_time");
				char buf[256] = { 0x0 };
				int n = 0;
				std::vector<unsigned short>::iterator iter_res;
				for (iter_res = data->begin(); iter_res != data->end(); iter_res++) {
					n += snprintf(buf + n, sizeof(buf) - n, "%s%d", n ? "|" : "", *iter_res);
					if (n > 240) {
						cJSON_AddItemToArray(array_res, cJSON_CreateString(buf));
						memset(buf, 0x0, sizeof(buf));
						n = 0;
						flag = true;
					}
				}
				if (n) {
					cJSON_AddItemToArray(array_res, cJSON_CreateString(buf));
					flag = true;
				}
				data->clear();
				
			}
			if (item) {
				cJSON_AddStringToObject(item, "name", iter_api->first.c_str());
				cJSON_AddItemToArray(api, item);
			} 
		}
		if (flag) {
			cJSON_AddItemToObject(task_root, "api", api);
			task_flag = true;
		} 
		else cJSON_Delete(api);
	}
	
	if (!task->reportData.error1->empty()) {
		task->reportData.error_lock->lock();
		std::swap(task->reportData.error1, task->reportData.error2);
		task->reportData.error_lock->unlock();

		cJSON* error = cJSON_CreateArray();
		std::vector<std::string>::iterator iter_error;
		if (!task->reportData.error2->empty()) {
			for (iter_error = task->reportData.error2->begin(); iter_error != task->reportData.error2->end(); ++iter_error) {
				cJSON_AddItemToArray(error, cJSON_CreateString((*iter_error).c_str()));
			}
			cJSON_AddItemToObject(task_root, "error", error);
			task_flag = true;
			task->reportData.error2->clear();
		}
		else cJSON_Delete(error);
	}

	if (task_flag) {
		cJSON_AddItemToArray(array, task_root);

		cJSON_AddNumberToObject(task_root, "task_id", task->taskID);
		cJSON_AddNumberToObject(task_root, "run_number", task->run_number);
	}
	else {
		cJSON_Delete(task_root);
	}
	return  task_flag;
}

int task_push_report_data(cJSON* array) {
	int ret = 0;
	std::map<int, ClientTaskConfig*>::iterator iter;
	for (iter = taskAll->begin(); iter != taskAll->end(); iter++) {
		if (task_push_report_data_detail(array, iter->second)) ret++;
	}
	for (iter = taskClean->begin(); iter != taskClean->end(); iter++) {
		if (task_push_report_data_detail(array, iter->second)) ret++;
	}
	return ret;
}

static hClientTaskConfig getTask_by_taskId(uint8_t taskID){
	std::map<int, hClientTaskConfig>::iterator iter;
	iter = taskAll->find(taskID);
	if (iter != taskAll->end()){
		return iter->second;
	}
	return NULL;
}

static void signal_call_user_init(BaseWorker* user, long long signal) {
	ReplayProtocol* proto = (ReplayProtocol*)user;
	hClientTaskConfig task = proto->Task;
	call_user_init(task, proto);
	proto->_timer = TimerCreate(user, NULL, 0, task->timer_out, userWorkFunc);
}

static int task_add_user(hClientTaskConfig task, int userCount, int userIndex){
	if (userCount <= 0){
		return 0;
	}
	ReplayProtocol* head = task->user_head, *user;
	ReplayProtocol* tail = head->prev;
	for (int i = 0; i < userCount; i++){
		user = get_user_from_free(task);
		if (!user) continue;
		user->Task = task;

		tail->next = user;
		user->next = head;

		head->prev = user;
		user->prev = tail;
		tail = user;

		user->thread_set();
		user->UserNumber = userIndex++;
		PostSignal(user, 0, signal_call_user_init);
	}
	return 0;
}

int __STDCALL create_new_task(int taskid, int runnumber, int projectid, int machineid, bool ignorerr, bool autostop, int userconut, int userindex, int loglevel, int logreport, const char* parms)
{
	ClientTaskConfig* task;
	task = task_new_data(taskid);
	if (task == NULL)
		return -1;

	task->taskID = taskid;
	task->run_number = runnumber;
	task->projectID = projectid;
	task->machineID = machineid;
	task->ignoreErr = ignorerr;
	size_t parm_len = strlen(parms) + 1;
	task->parms = (char*)malloc(parm_len);
	snprintf(task->parms, parm_len, "%s", parms);
	
	char path[256] = { 0x0 };
	snprintf(path, sizeof(path), "%s%ctask%d_p%d_m%d", LogPath, DIRChar, task->taskID, projectid, machineid);

	char command[256] = { 0x0 };
#ifdef __WINDOWS__
	snprintf(command, sizeof(command), "DEL /q %s* 2>nul", path);
	system(command);
#else
	snprintf(command, sizeof(command), "rm -f %s*", path);
	system(command);
#endif // __WINDOWS__

	task->report_log = logreport;
	task->logfd = RegisterLog(path, loglevel, 20, 0, 0);

	struct tm tmm;
	time_t now = NOWTIME;
#ifdef __WINDOWS__
	localtime_s(&tmm, &now);
#else
#define u_long unsigned long
	localtime_r(&now, &tmm);
#endif // __WINDOWS__
	LOG_Write(task->logfd, "\
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\
task_id:%d project_id:%d run_number:%d mac_id:%d datetime:%04d-%02d-%02d %02d:%02d:%02d\n\
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n", taskid, projectid, runnumber, machineid, tmm.tm_year + 1900, tmm.tm_mon + 1, tmm.tm_mday, tmm.tm_hour, tmm.tm_min, tmm.tm_sec);

	if (default_api.taskstart)
		default_api.taskstart(task);
	task->timer_out = config_get_int_value("agent", "timer", 200);
	task_add_user(task, userconut, userindex);
	return 0;
}

void __STDCALL set_task_log_level(uint8_t level, int taskID){
	hClientTaskConfig task = getTask_by_taskId(taskID);
	if (task != NULL){
		SetLogLevel(task->logfd, level);
	}
}

bool __STDCALL stop_task_by_id(int taskID){
	hClientTaskConfig task;
	std::map<int, hClientTaskConfig>::iterator iter;
	iter = taskAll->find(taskID);
	if (iter != taskAll->end()){
		task = iter->second;
		taskAll->erase(iter);
		task->status = TASK_CLEANING;
		taskClean->insert(std::pair<int, ClientTaskConfig*>(task->taskID, task));
		//run_task_stop_thread(task);
		LOG(clogId, LOG_DEBUG, "%s:%d Start Clean Task !\r\n", __func__, __LINE__);
		TimerCreate(AgentProto, task, 1, 1, destroy_task_stop_user);
		return true;
	}
	return false;
}

bool __STDCALL insert_message_by_taskId(int taskID, uint8_t event, int protocol, char* ip, uint32_t port, int sessionid, char* content, const char* note, uint64_t timestamp, uint32_t microsecond){
	hClientTaskConfig task;
	task = getTask_by_taskId(taskID);
	if (task == NULL) return false;
	if (task->stopMessageCache)
		return true;

	t_cache_message* message = (t_cache_message*)malloc(sizeof(t_cache_message));
	if (message == NULL){
		return false;
	}
	memset(message, 0x0, sizeof(t_cache_message));
	message->event = event;
	message->protocol = (PROTOCOL)protocol;
	if (event != TYPE_REINIT) {
		if (ip) {
			memcpy(message->ip, ip, strlen(ip));
		}
		message->port = port;
		message->sessionid = sessionid;
		if (content){
			size_t datalen = strlen(content);
			if (datalen) {
				char* data = base64decode(content, datalen, &datalen);
				if (!data) { free(message); return false; }
				message->content = data;
				message->contentlen = (uint32_t)datalen;
			}
			else {
				message->content = (char*)EMPTY_STRING;
				message->contentlen = 0;
			}
		}
		if (note) {
			size_t note_len = strlen(note);
			if (note_len == 0) {
				message->note = (char*)EMPTY_STRING;
				message->note_len = 0;
			}
			else {
				char* data = base64decode(note, note_len, &note_len);
				if (!data) { 
					if (message->content != EMPTY_STRING) free(message->content);
					free(message); 
					return false; 
				}
				message->note = data;
				message->note_len = (int)note_len;
			}
		}

		unsigned long long recordtime = (timestamp * 1000000 + microsecond) / 1000;
		if (task->messageList->empty()) {
			task->messageStartTime = recordtime;
		}
		message->recordtime = (unsigned long)(recordtime - task->messageStartTime);
		//printf("%s:%d %llu  %lu\n", __func__, __LINE__, recordtime, message->recordtime);
	}
	else {
		message->isloop = port;
		task->stopMessageCache = true;
	}
	task->messageList->push_back(message);
	return true;
}

int __STDCALL task_add_user_by_taskid(int taskid, int userCount, int userIndex){
	ClientTaskConfig* task;
	task = getTask_by_taskId(taskid);
	if (task == NULL)
		return -1;
	task_add_user(task, userCount, userIndex);
	return 0;
}

int __STDCALL task_filesync_done(){
	int ret = 0;
	if (default_api.filesync)
		ret = default_api.filesync();
	if (ret) return ret;

	ReplayProtocol* user, *next = userFree->next;
	while (true){
		user = next;
		if (user == userFree) break;
		next = next->next;
		user->_free();
	}
	userFree->next = userFree;
	userFree->prev = userFree;

	ReplayProtocol* tail = userFree->prev;
	int user_count = config_get_int_value("agent", "user_count", 0);
	for (int i = 0; i < user_count; ++i) {
		user = default_api.create();
		if (user) {
			tail->next = user;
			user->next = userFree;
			userFree->prev = user;
			user->prev = tail;
			tail = user;
		}
	}
	return ret;
}

void __STDCALL agent_callback() {
	if (default_api.agentcall)
		default_api.agentcall();
}

HSOCKET __STDCALL SocketConnect(ReplayProtocol* proto, const char* ip, int port, PROTOCOL protocol) {
	HSOCKET hsock = NULL;
	if (!AgentStaticIP_SIZE) {
		hsock = HsocketConnect(proto, ip, port, protocol);
	}
	else {
		int index = proto->UserNumber;
		index = index % AgentStaticIP_SIZE;
		hsock = HsocketBindConnect(proto, AgentStaticIP[index], 0, ip, port, protocol);
	}
	if (hsock)
		proto->ConnectionInsert(hsock, ip, port);
	return hsock;
}

void __STDCALL SocketClose(ReplayProtocol* proto, HSOCKET hsock){
	if (proto->ConnectionDelete(hsock))
		HsocketClosed(hsock);
}

bool __STDCALL	SocketSend(ReplayProtocol* proto, HSOCKET hsock, const char* data, int len) {
	std::map<HSOCKET, HConnectInfo>::iterator iter = proto->ConnInfo->find(hsock);
	if (iter != proto->ConnInfo->end()){
		HConnectInfo info = iter->second;
		info->appflowup += len;
		int i = len / 1500;
		int b = len % 1500;
		if (b) i++;
		info->netflowup += i * (18 + 60 + 60) + len;
		return HsocketSend(hsock, data, len);
	}
	return false;
}

void PlayStop(ReplayProtocol* proto, const char* fmt, ...){
	proto->user_status.PlayStop = true;
	va_list ap;
	va_start(ap, fmt);
	vsnprintf(proto->stop_reason, UserErrorSize - 1, fmt, ap);
	va_end(ap);
}

void __STDCALL PlayPause(ReplayProtocol* proto) {
	proto->user_status.PlayPause = true;
#ifdef USER_PAUSE_COUNT
	proto->user_pause_count++;
#endif
}

void __STDCALL PlayNormal(ReplayProtocol* proto) {
#ifndef USER_PAUSE_COUNT
	proto->user_status.PlayPause = false;
#else
	if (proto->user_pause_count > 0) proto->user_pause_count--;
	if (proto->user_pause_count == 0) proto->user_status.PlayPause = false;
#endif
}

void __STDCALL PlayFast(ReplayProtocol* proto, char fast) {
	proto->user_status.PlayFast = fast;
}

int __STDCALL PlayStep(ReplayProtocol* proto) {
	return proto->_fram_data.MsgPointer.index + 1;
}

int __STDCALL PlayStepSession(ReplayProtocol* proto) {
	int index = proto->_fram_data.MsgPointer.index;
	t_cache_message* msg = (*(proto->Task->messageList))[index - 1];
	return msg->sessionid;
}

char* __STDCALL PlayStepNote(ReplayProtocol* proto) {
	int index = proto->_fram_data.MsgPointer.index;
	t_cache_message* msg = (*(proto->Task->messageList))[index - 1];
	return msg->note;
}

void __STDCALL PlayStepBack(ReplayProtocol* proto, int index) {
	t_cache_message* msg = (*(proto->Task->messageList))[index];
	MSGPointer* pointer = &proto->_fram_data.MsgPointer;
	pointer->index = index;
	pointer->start_real = pointer->last - msg->recordtime;
}

void __STDCALL PlayAction(ReplayProtocol* proto, int action) {
	if (action & ACTION_WAIT) { PlayPause(proto); }
	if (action & ACTION_PAUSE) { PlayPause(proto); }
	else if (action & ACTION_PLAY) { PlayNormal(proto); }
}

void __STDCALL PlayNoStop(ReplayProtocol* proto) {
	proto->user_status.NotAutoStop = true;
}

int __STDCALL PlayOver(ReplayProtocol* proto) {
	hClientTaskConfig task = proto->Task;
	return  task->stopMessageCache && proto->_fram_data.MsgPointer.index == task->messageList->size();
}

void __STDCALL TaskUserReportMessage(ReplayProtocol* proto, const char* msg, size_t msgsz){
	size_t size = 0;
	char* b64 = base64encode(msg, msgsz, &size);
	if (b64) {
		//AgentProto->TaskUserReport(b64, size);
		free(b64);
	}
}

void __STDCALL	ReportConnectEvent(ReplayProtocol* proto, HSOCKET hsock, const char* addr, int ret) {
	hClientTaskConfig task = proto->Task;
	std::map<std::string, AgentReportInfoConnect*>::iterator iter;
	AgentReportInfoConnect* info = NULL;
TRY:
	iter = task->reportData.connect->find(addr);
	if (iter != task->reportData.connect->end()) {
		info = iter->second;
		ret == 0 ? AtomicAdd(info->success, 1) : AtomicAdd(info->faile, 1);
	}
	else {
		info = (AgentReportInfoConnect*)malloc(sizeof(AgentReportInfoConnect));
		if (info) {
			memset(info, 0x0, sizeof(AgentReportInfoConnect));
			task->reportData.connect_lock->lock();
			bool res = task->reportData.connect->insert(std::make_pair(addr, info)).second;
			task->reportData.connect_lock->unlock();
			if (!res) {
				free(info);
				goto TRY;
			}
			ret == 0 ? AtomicAdd(info->success, 1) : AtomicAdd(info->faile, 1);
		}
	}
}

void __STDCALL	ReportNetflowEvent(ReplayProtocol* proto, HSOCKET hsock, const char* addr, int app_flow_up, int app_flow_down, int net_flow_up, int net_flow_down) {
	hClientTaskConfig task = proto->Task;
	std::map<std::string, AgentReportInfoConnect*>::iterator iter;
	iter = task->reportData.connect->find(addr);
	if (iter != task->reportData.connect->end()) {
		AgentReportInfoConnect* info = iter->second;
		AtomicAdd(info->app_flow_up, app_flow_up);
		AtomicAdd(info->app_flow_down, app_flow_down);
		AtomicAdd(info->net_flow_up, net_flow_up);
		AtomicAdd(info->net_flow_down, net_flow_down);
	}
}

void __STDCALL ReportOnline(ReplayProtocol* proto) {
	if (!proto->user_status.UserOnline) {
		proto->user_status.UserOnline = true;
		hClientTaskConfig task = proto->Task;
		AtomicAdd(task->reportData.user_online, 1);
	}
}

void __STDCALL ReportOffline(ReplayProtocol* proto) {
	if (proto->user_status.UserOnline) {
		proto->user_status.UserOnline = false;
		hClientTaskConfig task = proto->Task;
		AtomicSub(task->reportData.user_online, 1);
	}
}

void __STDCALL ReportCounter(ReplayProtocol* proto, const char* name, int value, int counter_type, int space_time) {
	hClientTaskConfig task = proto->Task;
	std::map<std::string, AgentReportInfoCounter*>::iterator iter;
	AgentReportInfoCounter* info = NULL;
	TRY:
	iter = task->reportData.counter->find(name);
	if (iter != task->reportData.counter->end()) {
		info = iter->second;
		AtomicAdd(info->value, value);
	}
	else {
		info = (AgentReportInfoCounter*)malloc(sizeof(AgentReportInfoCounter));
		if (info) {
			memset(info, 0x0, sizeof(AgentReportInfoCounter));
			task->reportData.counter_lock->lock();
			bool res = task->reportData.counter->insert(std::make_pair(name, info)).second;
			task->reportData.counter_lock->unlock();
			if (!res) {
				free(info);
				goto TRY;
			}
			AtomicAdd(info->value, value);
			info->stype = counter_type;
			info->space_time = space_time;
		}
	}
}

void __STDCALL ReportApiResponse(ReplayProtocol* proto, const char* api, int response_time) {
	hClientTaskConfig task = proto->Task;
	std::map<std::string, AgentReportInfoApi*>::iterator iter;
	AgentReportInfoApi* info = NULL;
	TRY:
	iter = task->reportData.api->find(api);
	if (iter != task->reportData.api->end()) {
		info = iter->second;
		if (response_time >= 0) {
			info->data_lock->lock();
			info->data1->push_back(response_time);
			info->data_lock->unlock();
		}
		else {
			AtomicAdd(info->error_count, -response_time);
		}
	}
	else {
		info = (AgentReportInfoApi*)malloc(sizeof(AgentReportInfoApi));
		if (info) {
			memset(info, 0x0, sizeof(AgentReportInfoApi));
			info->data1 = new(std::nothrow) std::vector<unsigned short>;
			info->data2 = new(std::nothrow) std::vector<unsigned short>;
			info->data_lock = new(std::nothrow) std::mutex;
			task->reportData.api_lock->lock();
			bool res = task->reportData.api->insert(std::make_pair(api, info)).second;
			task->reportData.api_lock->unlock();
			if (!res) {
				delete info->data1;
				delete info->data2;
				delete info->data_lock;
				free(info);
				goto TRY;
			}
			if (response_time >= 0) {
				info->data_lock->lock();
				info->data1->push_back(response_time);
				info->data_lock->unlock();
			}
			else {
				AtomicAdd(info->error_count, -response_time);
			}
		}
	}
}

void __STDCALL ReportApiSend(ReplayProtocol* proto, const char* api, int send_flow, int send_count) {
	hClientTaskConfig task = proto->Task;
	std::map<std::string, AgentReportInfoApi*>::iterator iter;
	AgentReportInfoApi* info = NULL;
TRY:
	iter = task->reportData.api->find(api);
	if (iter != task->reportData.api->end()) {
		info = iter->second;
		AtomicAdd(info->send_flow, send_flow);
		AtomicAdd(info->send_count, send_count);
	}
	else {
		info = (AgentReportInfoApi*)malloc(sizeof(AgentReportInfoApi));
		if (info) {
			memset(info, 0x0, sizeof(AgentReportInfoApi));
			info->data1 = new(std::nothrow) std::vector<unsigned short>;
			info->data2 = new(std::nothrow) std::vector<unsigned short>;
			info->data_lock = new(std::nothrow) std::mutex;
			task->reportData.api_lock->lock();
			bool res = task->reportData.api->insert(std::make_pair(api, info)).second;
			task->reportData.api_lock->unlock();
			if (!res) {
				delete info->data1;
				delete info->data2;
				delete info->data_lock;
				free(info);
				goto TRY;
			}
			AtomicAdd(info->send_flow, send_flow);
			AtomicAdd(info->send_count, send_count);
		}
	}
}

void __STDCALL ReportApiRecv(ReplayProtocol* proto, const char* api, int recv_flow, int recv_count) {
	hClientTaskConfig task = proto->Task;
	std::map<std::string, AgentReportInfoApi*>::iterator iter;
	AgentReportInfoApi* info = NULL;
TRY:
	iter = task->reportData.api->find(api);
	if (iter != task->reportData.api->end()) {
		info = iter->second;
		AtomicAdd(info->recv_flow, recv_flow);
		AtomicAdd(info->recv_count, recv_count);
	}
	else {
		info = (AgentReportInfoApi*)malloc(sizeof(AgentReportInfoApi));
		if (info) {
			memset(info, 0x0, sizeof(AgentReportInfoApi));
			info->data1 = new(std::nothrow) std::vector<unsigned short>;
			info->data2 = new(std::nothrow) std::vector<unsigned short>;
			info->data_lock = new(std::nothrow) std::mutex;
			task->reportData.api_lock->lock();
			bool res = task->reportData.api->insert(std::make_pair(api, info)).second;
			task->reportData.api_lock->unlock();
			if (!res) {
				delete info->data1;
				delete info->data2;
				delete info->data_lock;
				free(info);
				goto TRY;
			}
			AtomicAdd(info->recv_flow, recv_flow);
			AtomicAdd(info->recv_count, recv_count);
		}
	}
}

void ReportOverMessage(ReplayProtocol* proto, const char* fmt, ...) {
	va_list ap;
	va_start(ap, fmt);
	vsnprintf(proto->stop_reason + UserErrorSize, UserErrorSize - 1, fmt, ap);
	va_end(ap);
}

long long __STDCALL Microsecond() {
	return GetSysTimeMicros();
}

void TaskAgentLog(uint8_t level, const char* fmt, ...){
	int logfd = clogId;
	if (logfd < 0 || CheckLogLevel(logfd, level))
		return;

	int l;
	char buf[MAX_LOG_LEN];
	struct tm tmm;
	time_t now = NOWTIME;
#ifdef __WINDOWS__
	localtime_s(&tmm, &now);
#else
	localtime_r(&now, &tmm);
#endif // __WINDOWS__
	char* slog = GetLogStr(level);
	l = snprintf(buf, MAX_LOG_LEN - 1, "[%s:%lu]:[%04d-%02d-%02d %02d:%02d:%02d]", slog, (u_long)THREAD_ID, tmm.tm_year + 1900, tmm.tm_mon + 1, tmm.tm_mday, tmm.tm_hour, tmm.tm_min, tmm.tm_sec);

	va_list ap;
	va_start(ap, fmt);
	l += vsnprintf(buf + l, (size_t)MAX_LOG_LEN - l - 1, fmt, ap);
	va_end(ap);
	l += snprintf(buf + l, (size_t)MAX_LOG_LEN - l - 1, "\r\n");

#ifdef __WINDOWS__
	WriteFile(GetLogFileHandle(logfd), buf, l, &_log_written, NULL);
#else
	write(GetLogFileHandle(logfd), buf, l);
#endif // __WINDOWS__
	if (log_stdout) printf("%.*s", l, buf);
}

void TaskLog(hClientTaskConfig task, uint8_t level, const char* fmt, ...){
	int logfd = task->logfd;
	if (logfd < 0 || CheckLogLevel(logfd, level))
		return;
	
	int l;
	char buf[MAX_LOG_LEN];
	struct tm tmm;
	time_t now = NOWTIME;
#ifdef __WINDOWS__
	localtime_s(&tmm, &now);
#else
	localtime_r(&now, &tmm);
#endif // __WINDOWS__
	char* slog = GetLogStr(level);
	l = snprintf(buf, MAX_LOG_LEN - 1, "[%s:%lu]:[%04d-%02d-%02d %02d:%02d:%02d]", slog, (u_long)THREAD_ID, tmm.tm_year + 1900, tmm.tm_mon + 1, tmm.tm_mday, tmm.tm_hour, tmm.tm_min, tmm.tm_sec);

	va_list ap;
	va_start(ap, fmt);
	l += vsnprintf(buf + l, (size_t)MAX_LOG_LEN - l - 1, fmt, ap);
	va_end(ap);
	l += snprintf(buf + l, (size_t)MAX_LOG_LEN - l - 1, "\r\n");

#ifdef __WINDOWS__
	WriteFile(GetLogFileHandle(logfd), buf, l, &_log_written, NULL);
#else
	write(GetLogFileHandle(logfd), buf, l);
#endif // __WINDOWS__
	if (log_stdout) printf("%.*s", l, buf);
}

void TaskUserLog(ReplayProtocol* proto, uint8_t level, const char* fmt, ...){
	int logfd = proto->Task->logfd;
	if (logfd < 0 || CheckLogLevel(logfd, level))
		return;

	int l;
	char buf[MAX_LOG_LEN] = {0x0};
	struct tm tmm;
	time_t now = NOWTIME;
#ifdef __WINDOWS__
	localtime_s(&tmm, &now);
#else
	localtime_r(&now, &tmm);
#endif // __WINDOWS__
	char* slog = GetLogStr(level);
	l = snprintf(buf, MAX_LOG_LEN - 1, "[%s:%lu]\t[NO.%d:%d][%04d-%02d-%02d %02d:%02d:%02d]", slog, (u_long)THREAD_ID, proto->UserNumber, proto->_fram_data.MsgPointer.index, tmm.tm_year + 1900, tmm.tm_mon + 1, tmm.tm_mday, tmm.tm_hour, tmm.tm_min, tmm.tm_sec);

	va_list ap;
	va_start(ap, fmt);
	l += vsnprintf(buf + l, (size_t)MAX_LOG_LEN - l - 1, fmt, ap);
	va_end(ap);
	l += snprintf(buf + l, (size_t)MAX_LOG_LEN - l - 1, "\r\n");

#ifdef __WINDOWS__
	HANDLE fd = GetLogFileHandle(logfd);
	WriteFile(fd, buf, l, &_log_written, NULL);
#else
	write(GetLogFileHandle(logfd), buf, l);
#endif // __WINDOWS__
	if (log_stdout) printf("%.*s", l, buf);
}

static void TaskManagerForever(int projectid, const char* groupid, bool server) {
#ifdef __WINDOWS__
	char url[32] = { 0x0 };
#define clear_screen "CLS"
#else
#define clear_screen "clear"
	if (ShowConsole == false){
		while (1) { //如果linux下不需要控制台，直接休眠即可
			TimeSleep(30000);
		}
	}
#endif
	//system(clear_screen);
	//printf("正在启动……");
	//TimeSleep(1000);
	char in[16] = { 0x0 };
	char host[64] = { 0x0 };
	char project[16] = { 0x0 };
	if (strchr(AgentManagerIP, ':')) {
		snprintf(host, sizeof(host), "[%s]:%d", AgentManagerIP, AgentManagerPort);
	}
	else {
		snprintf(host, sizeof(host), "%s:%d", AgentManagerIP, AgentManagerPort);
	}
	snprintf(project, sizeof(project), "%d", projectid);
	const char* project_name = config_get_string_value("project", project, "未配置");
	const char* mode = server ? "单机" : "负载端";
	char server_info[256] = {0x0};
	while (true){
		system(clear_screen);
		server_info[0] = 0x0;
		if (server){
			snprintf(server_info, sizeof(server_info), "\n%s\n代理扩展：%s\n", ServerInfoString, proxy_hook?"开":"关");
		}
		printf("%s\n了解更多http://supersheeps.cn\n正在运行%s模式，后台访问：http://%s\n\
%s\n\
负载端：%d号项目[%s]-[%s]组\n控制端：%s[%s]\n%s静态IP(%zd个)：%s\n资源同步：%s\n控制台日志打印：%s\n状态：%s\n\n\
选择:【0.管理后台】【1.主页】【2.静态IP】【3.资源同步】【4.控制台日志打印】%s【Quit退出】\n操作：\n", 
			TaskAgentWelcome, mode, host, 
			server_info , projectid, project_name, groupid, TaskManagerRuning ? "已连接" : "未连接", host,
			TaskAgentInfoString, AgentStaticIP.size(), AgentStaticIP_SIZE ? "开" : "关", AgentSyncFile ? "开" : "关", log_stdout ? "开" : "关", TaskAgentStatMsg, server ? "【5.重载扩展脚本】【6.代理扩展】":"");
		if (TaskAgentState == STATE_READY_NONE) {
			TimeSleep(1000);
			continue;
		}
		fgets(in, 16, stdin);
		if (in[0] == 'Q' && in[1] == 'u' && in[2] == 'i' && in[3] == 't')
			break;
		else if (in[0] == '6' && server) {
			proxy_hook = !proxy_hook;
		}
		else if (in[0] == '5' && server) {
			server_hook_reinit();
		}
		else if (in[0] == '4') {
			log_stdout = !log_stdout;
		}
		else if (in[0] == '3') {
			AgentSyncFile = AgentSyncFile ? 0 : 1;
		}
		else if (in[0] == '2') {
			AgentStaticIP_SIZE = AgentStaticIP_SIZE ? 0 : agent_virtual_ip_load();
		}
		else if (in[0] == '1') {
		//else if (in[0] == 'H' && in[1] == 'o' && in[2] == 'm' && in[3] == 'e') {
#ifdef __WINDOWS__
			snprintf(url, sizeof(url), "http://supersheeps.cn/");
			HINSTANCE res = ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
#endif
		}
		else if (in[0] == '0' ) {
		//else if (in[0] == 'M' && in[1] == 'a' && in[2] == 'n' && in[3] == 'a' && in[4] == 'g' && in[5] == 'e' && in[6] == 'r') {
#ifdef __WINDOWS__
			snprintf(url, sizeof(url), "http://%s", host);
			HINSTANCE res = ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
#endif
		}
	}
}

void __STDCALL TaskManagerRun(int projectid, const char* groupid, int server, const char* ip, int port, 
	FILES_SYNC_CALLBACK filesync, AGENT_CALLBACK agent, CREATE_USER_CALLBACK create, TASK_CALLBACK taskstart, TASK_CALLBACK taskstop){
	default_api.filesync = filesync;
	default_api.agentcall = agent;
	default_api.create = create;
	default_api.taskstart = taskstart;
	default_api.taskstop = taskstop;

	AgentProjectid = projectid;
	if (groupid == NULL) {
		groupid = config_get_string_value("agent", "group_id", DEFAUT_GROUP);
	}
	snprintf(AgentGroupid, sizeof(AgentGroupid), "%s", groupid);

	if (server) {
		snprintf(AgentManagerIP, sizeof(AgentManagerIP), "%s", "::1");
	}
	else if (ip) {
		snprintf(AgentManagerIP, sizeof(AgentManagerIP), "%s", ip);
	}
	else {
		ip = config_get_string_value("common", "srv_ip", "::1");
		snprintf(AgentManagerIP, sizeof(AgentManagerIP), "%s", ip);
	}
	if (port > 0) AgentManagerPort = port;
	else { AgentManagerPort = config_get_int_value("common", "srv_port", 1080); }

	if (!SheepsRun("::", server ? AgentManagerPort : 0)) {
		log_stdout = config_get_bool_value("agent", "log_stdout", false);
		TaskManagerForever(projectid, AgentGroupid, server);
	}
	else{
		system("pause");
	}
}